﻿/**
 * 判断一个对象是不是数组
 * @name Array.isArray
 * @function
 * @grammar Array.isArray(vArg)
 * @param {Any} vArg 需要判断的对象
 *
 * @example
 * Array.isArray(myobj);
 * 
 * @returns {Boolean} 判断结果
 */
if(!Array.isArray) Array.isArray = function (vArg) {
  return Object.prototype.toString.call(vArg) === "[object Array]";
};

/**
 * 从前往后，查询数组中指定元素的索引位置
 * @name Array.indexOf
 * @function
 * @grammar Array.indexOf(match[, fromIndex])
 * @param {Any} match 查询项
 * @param {Number} [fromIndex] 查询的起始位索引位置，如果为负数，则从Array.length + fromIndex往后开始查找
 * @memberOf Array#
 * @todo 测试todo功能
 *
 * @example
 * var myarray = [2,4,9,10,28,10,19];
 * myarray.indexOf(10);
 * @result 3
 * 
 * @returns {Number} 指定元素的索引位置，查询不到时返回-1
 */
if(!Array.prototype.indexOf) Array.prototype.indexOf = function(match, fromIndex) {
  var len = this.length;
  fromIndex |= 0;
  if(fromIndex < 0) {
    fromIndex = Math.max(0, len + fromIndex)
  }
  for ( ; fromIndex < len; fromIndex++) {
    if(fromIndex in this && this[fromIndex] === match) {
      return fromIndex;
    }
  }
  return -1;
};

/**
 * 从后往前，查询数组中指定元素的索引位置
 * @name Array.lastIndexOf
 * @function
 * @grammar Array.lastIndexOf(match[, fromIndex])
 * @param {Any} match 查询项
 * @param {Number} [fromIndex] 查询的起始位索引位置，如果为负数，则从source.length+fromIndex往前开始查找
 * @memberOf Array#
 *
 * @example
 * var myarray = [2,4,9,10,28,10,19];
 * myarray.lastIndexOf(10);
 * @result 5
 * 
 * @returns {Number} 指定元素的索引位置，查询不到时返回-1
 */
if(!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(match, fromIndex) {
    var len = source.length >>> 0;
    fromIndex |= 0;
    if(!fromIndex || fromIndex >= len) {
      fromIndex = len - 1;
    }
    if(fromIndex < 0){
      fromIndex += len;
    }
    for(; fromIndex >= 0; fromIndex--){
      if(fromIndex in source && source[fromIndex] === match){
        return fromIndex;
      }
    }
    return -1;
};

/**
 * 遍历数组，验证数组中的每一个元素是否符合回调函数指定的规则。如数组中的每一项都符合回调函数指定的规则，则返回true，否则返回false
 * @name Array.every
 * @function
 * @grammar Array.every(fun[, thisp])
 * @param {Function} fun 需要执行的回调函数
 * @param {Any} [thisp] fun函数中this关键字指向的内容
 * @memberOf Array#
 *
 * @example
 * var myarray = [2,4,9,10,28,10,19];
 * myarray.every(function(value, index, obj){
 *   return value > 2;
 * });
 * @result false
 * 
 * 
 * @returns {Boolean} 数组中的每一项是否符合指定的规则
 */
if (!Array.prototype.every) Array.prototype.every = function(fun, thisp) {
  if (typeof fun != "function") throw new TypeError();
  //使用new Object定义变量t，防止fun对原数组造成破坏
  var t = new Object(this), len = t.length >>> 0;
  for (var i = 0; i < len; i++) {
    if (i in t && !fun.call(thisp, t[i], i, t)) return false;
  }
  return true;
};

/**
 * 遍历数组，把符合回调函数指定规则的元素组成一个新的数组并返回
 * @name Array.filter
 * @function
 * @grammar Array.filter(fun[, thisp])
 * @param {Function} fun 需要执行的回调函数
 * @param {Any} [thisp] fun函数中this关键字指向的内容
 * @memberOf Array#
 *
 * @example
 * var myarray = [2,4,9,10,28,10,19];
 * myarray.filter(function(value, index, obj){
 *   return value > 10;
 * });
 * @result [28,19]
 * 
 * @returns {Array} 过滤后的新数组
 */
if (!Array.prototype.filter) Array.prototype.filter = function(fun, thisp) {
  if (typeof fun != "function") throw new TypeError();
  var t = new Object(this), len = t.length >>> 0, res = [];
  for (var i = 0; i < len; i++) {
    if (i in t) {
      var val = t[i];
      if (fun.call(thisp, val, i, t)) res.push(val);
    }
  }
  return res;
};

/**
 * 在数组中的每一个项运行一个函数，并将所有的结果作为数组返回
 * @name Array.map
 * @function
 * @grammar Array.map(fun[, thisp])
 * @param {Function} fun 需要执行的回调函数
 * @param {Any} [thisp] fun函数中this关键字指向的内容
 * @memberOf Array#
 *
 * @example
 * var myarray = [2,4,9,10,28,10,19];
 * myarray.map(function(value, index, obj){
 *   return value + 1;
 * });
 * @result [3,5,10,11,29,11,20]
 * 
 * @returns {Array} 遍历后的新数组
 */
if (!Array.prototype.map) Array.prototype.map = function(fun, thisp) {
  if(typeof fun != 'function') throw new TypeError();
  var len = this.length >>> 0, res = new Array(len);
  for(var i = 0; i < len; i++) {
    if(i in this) res[i] = fun.call(thisp, this[i], i, this);
  }
  return res;
};

/**
 * 在数组中的每一个项运行一个函数，并将所有的结果作为数组返回
 * @name Array.forEach
 * @function
 * @grammar Array.forEach(fun[, thisp])
 * @param {Function} fun 需要执行的回调函数
 * @param {Any} [thisp] fun函数中this关键字指向的内容
 * @memberOf Array#
 * @see Array.map
 * 
 * @returns {Array} 遍历后的新数组
 */
if(!Array.prototype.forEach) Array.prototype.forEach = function( fun, thisp ) {
  this.map(fun, thisp);
};

/**
 * 遍历数组，验证数组是否有某项元素符合回调函数指定的规则。如数组中存在符合验证规则的项，则返回true，否则返回false
 * @name Array.some
 * @function
 * @grammar Array.some(fun[, thisp])
 * @param {Function} fun 需要执行的回调函数
 * @param {Any} [thisp] fun函数中this关键字指向的内容
 * @memberOf Array#
 *
 * @example
 * var myarray = [2,4,9,10,28,10,19];
 * myarray.some(function(value, index, obj){
 *   return value < 3;
 * });
 * @result true
 * 
 * @returns {Boolean} 数组中是否存在符合规则的项
 */
if (!Array.prototype.some) Array.prototype.some = function(fun, thisp) {
  if (typeof fun != "function") throw new TypeError();
  var t = new Object(this), len = t.length >>> 0;
  for (var i = 0; i < len; i++) {
    if (i in t && fun.call(thisp, t[i], i, t)) return true;
  }
  return false;
};

/**
 * 对数组中的所有元素调用指定的回调函数。该回调函数的返回值为累积结果，并且此返回值在下一次调用该回调函数时作为参数提供。 
 * @name Array.reduce
 * @function
 * @grammar Array.reduce(accumulator[, thisp])
 * @param {Function} accumulator 需要执行的回调函数
 * 
 * @returns {Boolean} 通过运算后的累计结果
 */
if (!Array.prototype.reduce) Array.prototype.reduce = function reduce(accumulator) {
  if (this===null || this===undefined) throw new TypeError("Object is null or undefined");
  var i = 0, l = this.length >> 0, curr;
  if(typeof accumulator !== "function") // ES5 : "If IsCallable(callbackfn) is false, throw a TypeError exception."
    throw new TypeError("First argument is not callable");
  if(arguments.length < 2) {
    if (l === 0) throw new TypeError("Array length is 0 and no second argument");
    curr = this[0];
    i = 1; // start accumulating at the second element
  } else {
    curr = arguments[1];
  }
  while (i < l) {
    if(i in this) curr = accumulator.call(undefined, curr, this[i], i, this);
    ++i;
  }
  return curr;
};

/**
 * 按降序顺序对数组中的所有元素调用指定的回调函数。该回调函数的返回值为累积结果，并且此返回值在下一次调用该回调函数时作为参数提供。
 * @name Array.reduceRight
 * @function
 * @grammar Array.reduceRight(accumulator[, thisp])
 * @param {Function} accumulator 需要执行的回调函数
 * 
 * @returns {Boolean} 通过运算后的累计结果
 */
if (!Array.prototype.reduceRight) Array.prototype.reduceRight = function(callbackfn, initialValue) {
  if (this == null) throw new TypeError();
  var t = Object(this);
  var len = t.length >>> 0;
  if (typeof callbackfn != "function") throw new TypeError(); // no value to return if no initial value, empty array
  if (len === 0 && arguments.length === 1) throw new TypeError();
  var k = len - 1;
  var accumulator;
  if (arguments.length >= 2) {
    accumulator = arguments[1];
  } else {
    do {
      if (k in this) {
        accumulator = this[k--];
        break;
      } // if array contains no values, no initial value to return
      if (--k < 0) throw new TypeError();
    } while (true);
  }
  while (k >= 0) {
    if (k in t) accumulator = callbackfn.call(undefined, accumulator, t[k], k, t);
    k--;
  }
  return accumulator;
};